package com.epam.training.myspringioc.reader;

import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;

import org.xml.sax.SAXException;

import com.epam.training.myspringioc.BeanDefinition;
import com.epam.training.myspringioc.parsers.Parser;
import com.epam.training.myspringioc.parsers.ParserTypes;
import com.epam.training.myspringioc.parsers.XMLDOMParser;

/**
 * 
 * @author bogdan
 *
 */
public class XmlBeanDefinitionReaderImpl implements XmlBeanDefinitionReader {
	private boolean validate;
	private Parser parser;
	private Map<String, BeanDefinition> beanDefinitions;

	public static final String XMLSCHEMA = "http://www.w3.org/2001/XMLSchema";

	public XmlBeanDefinitionReaderImpl() {
		validate = false;
		parser = new XMLDOMParser();
	}

	public Map<String, BeanDefinition> getBeanDefenitions() {
		return beanDefinitions;
	}

	@Override
	public void loadBeanDefinitions(String configName) {
		if (validate && !validateXml(configName)) {
			throw new NotValidXmlException();
		}

		beanDefinitions = parser.parseXml(configName);
	}

	@Override
	public void setValidating(boolean validating) {
		this.validate = validating;
	}

	@Override
	public void setParserType(ParserTypes parserType) {
		switch (parserType) {
		case DOM:
			parser = new XMLDOMParser();
			break;
		case SAX:
		case STAX:
			break;
		default:
			throw new IllegalStateException();
		}

	}

	/**
	 * Validate XML cobfigure file
	 * 
	 * @param XMLfileName
	 * @return
	 */
	private boolean validateXml(String xmlfileName) {
		SchemaFactory factory = SchemaFactory.newInstance(XMLSCHEMA);

		try {
			Schema schema = factory.newSchema();
			Validator validator = schema.newValidator();

			Source source = new StreamSource(xmlfileName);
			validator.validate(source);
		} catch (SAXException | IOException e) {
			Logger.getLogger(XmlBeanDefinitionReaderImpl.class.getName()).log(
					Level.SEVERE, null, e);
			return false;
		}

		return true;
	}

	@Override
	public Map<String, BeanDefinition> getBeanDefinition() {
		return beanDefinitions;
	}

}
